#include <string.h>
#include "unity.h"
#include "double_list.h"
#include "student_data.h"
#include "student_interface.h"

extern struct list_head student_list;

/* Test data */
static student_info_t test_student1 = {
        .id = "123",
	.name = "Alice",
	.gender = FEMALE,
	.dob = "2000-01-01"
};

static student_info_t test_student2 = {
	.id = "456",
	.name = "Bob",
	.gender = MALE,
	.dob = "1999-12-31"
};

/* Setup function */
void setUp(void)
{
        INIT_LIST_HEAD(&student_list);
	/* Clear the linked list */
}

/* Teardown function */
void tearDown(void)
{
	/* Add cleanup code here if necessary */
}

/* Test adding student */
void test_data_add_student(void)
{
	TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student1));
	TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student2));
}

/* Test deleting student by ID */
void test_data_delete_student_id(void)
{
    student_info_t deleted_student;

    TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student1));
    TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student2));

    TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                      data_delete_student_id("123", &deleted_student));

    TEST_ASSERT_EQUAL_STRING("123", deleted_student.id);
    TEST_ASSERT_EQUAL_STRING("Alice", deleted_student.name);

    TEST_ASSERT_EQUAL(STATUS_NOT_FOUND,
                      data_query_student_id("123", &deleted_student));
}

/* Test deleting student by name */
void test_data_delete_student_name(void)
{
    student_info_t deleted_student;

    TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student1));
    TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student2));

    TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                      data_delete_student_name("Alice", &deleted_student));

    TEST_ASSERT_EQUAL_STRING("123", deleted_student.id);
    TEST_ASSERT_EQUAL_STRING("Alice", deleted_student.name);

    TEST_ASSERT_EQUAL(STATUS_NOT_FOUND,
                      data_query_student_name("Alice", &deleted_student));
}

/* Test updating student information */
void test_data_update_student(void)
{
        TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student1));

        student_info_t updated_student1 = {
                .id = "123",
                .name = "Alice Smith",
                .gender = FEMALE,
                .dob = "2001-02-02"
        };

        TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                          data_update_student(&updated_student1));

        student_node_t *pos;
        list_for_each_entry(pos, &student_list, list) {
                if (strcmp(pos->info.id, "123") == 0) {
                        TEST_ASSERT_EQUAL_STRING("Alice Smith",
                                                 pos->info.name);
                        TEST_ASSERT_EQUAL(FEMALE, pos->info.gender);
                        TEST_ASSERT_EQUAL_STRING("2001-02-02", pos->info.dob);
                }
        }

        student_info_t updated_student2 = {
                .id = "123",
                .name = "",
                .gender = OTHER,
                .dob = ""
        };

        TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                          data_update_student(&updated_student2));

        list_for_each_entry(pos, &student_list, list) {
                if (strcmp(pos->info.id, "123") == 0) {
                        TEST_ASSERT_EQUAL_STRING("Alice Smith",
                                                 pos->info.name);
                        TEST_ASSERT_EQUAL(OTHER, pos->info.gender);
                        TEST_ASSERT_EQUAL_STRING("2001-02-02",
                                                 pos->info.dob);
                }
        }

        student_info_t updated_student3 = {
                .id = "999",
                .name = "New Name",
                .gender = MALE,
                .dob = "1999-09-09"
        };

        TEST_ASSERT_EQUAL(STATUS_NOT_FOUND,
                          data_update_student(&updated_student3));
}

/* Test querying student information by ID */
void test_data_query_student_id(void)
{
	TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student1));

	student_info_t info;
	TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                   data_query_student_id("123", &info));

	TEST_ASSERT_EQUAL_STRING("123", info.id);
	TEST_ASSERT_EQUAL_STRING("Alice", info.name);
	TEST_ASSERT_EQUAL(FEMALE, info.gender);
	TEST_ASSERT_EQUAL_STRING("2000-01-01", info.dob);
}

/* Test querying student information by name */
void test_data_query_student_name(void)
{
	TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student2));

	student_info_t info;
	TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                   data_query_student_name("Bob", &info));
	TEST_ASSERT_EQUAL_STRING("456", info.id);
	TEST_ASSERT_EQUAL_STRING("Bob", info.name);
	TEST_ASSERT_EQUAL(MALE, info.gender);
	TEST_ASSERT_EQUAL_STRING("1999-12-31", info.dob);
}

/* Test getting all student information */
void test_data_get_all_student(void)
{
	TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student1));
	TEST_ASSERT_EQUAL(STATUS_SUCCESS, data_add_student(&test_student2));

	student_info_t *students;
	size_t count;
	TEST_ASSERT_EQUAL(STATUS_SUCCESS,
                   data_get_all_student(&students, &count));
	TEST_ASSERT_EQUAL(2, count);

	TEST_ASSERT_NOT_NULL(students);
	TEST_ASSERT_EQUAL_STRING("123", students[0].id);
	TEST_ASSERT_EQUAL_STRING("Alice", students[0].name);
	TEST_ASSERT_EQUAL(FEMALE, students[0].gender);
	TEST_ASSERT_EQUAL_STRING("2000-01-01", students[0].dob);
	
	TEST_ASSERT_EQUAL_STRING("456", students[1].id);
	TEST_ASSERT_EQUAL_STRING("Bob", students[1].name);
	TEST_ASSERT_EQUAL(MALE, students[1].gender);
	TEST_ASSERT_EQUAL_STRING("1999-12-31", students[1].dob);

}

/* Main function */
int main(void)
{
	UNITY_BEGIN();

	RUN_TEST(test_data_add_student);
	RUN_TEST(test_data_delete_student_id);
	RUN_TEST(test_data_delete_student_name);
	RUN_TEST(test_data_update_student);
	RUN_TEST(test_data_query_student_id);
	RUN_TEST(test_data_query_student_name);
	RUN_TEST(test_data_get_all_student);

	return UNITY_END();
}
